import java.security.*;
import com.ibm.opencard.terminal.pcsc10.PcscException;
import swt.util.ByteArray;
import de.uniaugsburg.swt.javacard.terminalinterface.SWTReader;
import de.uniaugsburg.swt.javacard.terminalinterface.SWTTerminalInterface;

/**
 *Die Methode zur Transmission,Verschluesselung,Entschluesselung,Hashfunction
 *@Autor: Wei Zhao, Wei Zhang
 */

public class Crypto {	
	
	private final static String cryptProvider = "BC";
	
//	private Terminal leser=null;
	
	//fuer Ergebnis
	//byte[] response={(byte)0x00,(byte)0xc0,(byte)0x00,(byte)0x00,(byte)0x20};
	
	//public Crypto(Terminal t)
	public Crypto()
	{
		
	 // leser=t;
	}
	
	/**
	 *Erzeugung von Zufallszahlen
	 *@Autor: Wei Zhao, Wei Zhang
	 *@param n Laenge von Array  
	 *@return n byte Zufallszahlen
	 */
	public byte[] getRandomData(int n)
	{
		byte [] byte_array = new byte[n];
		java.security.SecureRandom rand = new java.security.SecureRandom();
		rand.nextBytes(byte_array);
		return byte_array;
	}
	
	/**
	 *Initial Transmission
	 *@Autor: Wei Zhao, Wei Zhang
	 *@param command verschiedene Ereignisse von Transmission
	 *@param key verwendeter Schluessel fuer verschiedene Firmen
	 *@param nonce Data zur terminalNonce
	 *@return 32-byte Array  0-7 Result  8-15 Nonce  16-31 Hashwert
	 */
	public byte[] initTransmission(byte command,byte userID,byte[] key,byte[] nonce)
	{
		

		byte[] tmpApduData=new byte[32];
		byte[] tmpApduCipher=new byte[16];		
		byte[] tmpApdu=new byte[38];		
		byte[] tmpResult=null;
		
		
		ByteArray.copy(getRandomData(8),0,tmpApduCipher,0,8);
		ByteArray.copy(nonce,0,tmpApduCipher,8,8);
		ByteArray.copy(encrypt(key,tmpApduCipher),0,tmpApduData,0,16);		
		ByteArray.copy(getRandomData(16),0,tmpApduData,16,16);
				
		//tmpApdu=leser.creatAPDU(command,userID,(byte)0x00,tmpApduData);
		
			return tmpApduData;	
		/*try
	    {
			
		//	tmpResult=leser.sendAPDU(tmpApdu);
		 //  tmpResult=leser.sendAPDU(response);

	    }
	    catch(Exception e)
	    {
	    	System.out.print(e.getMessage());
	    }
	    
	 
		if(tmpResult.length == 2)
		{
			//System.out.println("Falsches Ergebnis bei sendAPDU-Funktion in initTransmission!");
			//System.out.println("Ergebnislange soll nicht 2 sein--Funktion initTransmission--Class Crypto!");
			
			return null;
		}
			
		else
		{
			ByteArray.copy(tmpResult, 0, tmpApduCipher,0,16);
			tmpApduCipher=decrypt(key,tmpApduCipher);
			ByteArray.copy(tmpApduCipher, 0, tmpApduData, 0, 16);
			
			ByteArray.copy(tmpResult, 16, tmpApduData, 16, 16);
			return tmpApduData;
		}
			*/
	}
	
	
	/**
	 *Data Transmission
	 *@Autor: Wei Zhao, Wei Zhang
	 *@param key verwendeter Schluessel fuer verschiedene Firmen
	 *@param tN Data zur terminalNonce
	 *@param cN Data zur cardNonce
	 *@param data byte Array
	 *@return 32-byte Array  0-7 Result  8-15 Nonce  16-31 Hashwert
	 */
	
	public byte[] dataTransmission(byte command,byte userID,byte compyID,byte[] key,byte[] tN,byte[] cN,byte[] data)
	{
		
		byte[] tmpApduData=new byte[32];
		byte[] tmpApduCipher=new byte[16];
		
		//byte[] tmpApdu=new byte[38];
		
		//byte[] tmpResult=null;
		
		ByteArray.copy(data,0,tmpApduCipher,0,8);
		ByteArray.copy(tN,0,tmpApduCipher,8,8);
		ByteArray.copy(encrypt(key,tmpApduCipher),0,tmpApduData,0,16);		
		ByteArray.copy(hashWert(cN),0,tmpApduData,16,16);		
		return tmpApduData;
		//tmpApdu=leser.creatAPDU(command,userID,compyID,tmpApduData);
		
		/*
		try
	    {
			//tmpResult=leser.sendAPDU(tmpApdu);
		//	tmpResult=leser.sendAPDU(this.response);

	    }
	    catch(Exception e)
	    {
	    	System.out.print(e.getMessage());
	    }
	    
		if(tmpResult.length == 2)
		{
				}
			
		else
		{
					}
			*/
	}


	
	/**
	 * Verschluesselung
	 * @Autor: Wei Zhao, Wei Zhang
	 * @param key  verwendeter Schluessel
	 * @param to_encode  Daten zur Verschluesselung
	 * @return verschluesselte Daten
	 */
	public byte[] encrypt(byte[] key, byte[] to_encode){
		byte[] encode_data=null;
		
		java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		//javax.crypto.KeyGenerator keygen=javax.crypto.KeyGenerator.getInstance("DESede",cryptProvider);
		try {
			javax.crypto.SecretKeyFactory sessionkf= javax.crypto.SecretKeyFactory.getInstance("DESede",cryptProvider);
			javax.crypto.SecretKey the_key= sessionkf.generateSecret(new javax.crypto.spec.DESedeKeySpec(key));
			javax.crypto.Cipher cip =javax.crypto.Cipher.getInstance("DESede/ECB/NoPadding",cryptProvider);
			cip.init(javax.crypto.Cipher.ENCRYPT_MODE, the_key);
			encode_data = cip.doFinal(to_encode);
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		return encode_data;
	}
	
	
	/**
	 * Entschluesselung
	 * @Autor: Wei Zhao, Wei Zhang
	 * @param key  verwendeter Schluessel
	 * @param to_decode  Daten zur Entschluesselung
	 * @return Entschluesselte Daten
	 */
	public byte[] decrypt(byte[] key, byte[] to_decode){
		byte[] decode_data=null;
		java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		try {
			javax.crypto.SecretKeyFactory sessionkf= javax.crypto.SecretKeyFactory.getInstance("DESede",cryptProvider);
			javax.crypto.SecretKey the_key= sessionkf.generateSecret(new javax.crypto.spec.DESedeKeySpec(key));
			javax.crypto.Cipher cip =javax.crypto.Cipher.getInstance("DESede/ECB/NoPadding",cryptProvider);
			cip.init(javax.crypto.Cipher.DECRYPT_MODE, the_key);
			decode_data = cip.doFinal(to_decode);
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		return decode_data;
	}
	
	
	/**
	 * Hashfunktion
	 * @Autor: Wei Zhao, Wei Zhang
	 * @param to_hashcode  Daten zur Hash
	 * @return Hash Daten
	 */
	public byte[] hashWert(byte[] to_hashcode)
	{
		MessageDigest md;
		 byte[] hashcode_data=new byte[16];
		try{
			
			
			java.security.Security.addProvider(
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
			
			
			md=MessageDigest.getInstance("MD5", cryptProvider);
			hashcode_data=md.digest(to_hashcode);
			System.out.print(hashcode_data.length);
		}
		catch(Exception e)
		{
			System.out.print(e.getMessage());
		}
		
		return hashcode_data;
	}


}
